//
// Created by taojiaheng on 2020/6/3.
//

#include "Worker.h"

// 初始化静态变量
std::vector<Worker *> *Worker::worker_list = new std::vector<Worker *>();

Worker::~Worker() {
    delete pids;
}

void Worker::runAll(bool is_daemon) {
    if (is_daemon) {
        // 变为守护进程
        Worker::setMasterProcessIsDaemon();
    }
    // 初始化信号处理
    Worker::initSignal();
    // fork 所有的进程
    Worker::forkAllProcess();
    printf("主进程 PID = %d\n", getpid());
    // 等待
    while (true) {
        sleep(1);
    }
}

Worker::Worker(Socket * _socket) {
    socket = _socket;
}

void Worker::addWorker(Worker *worker) {
    worker_list->push_back(worker);
}

void Worker::forkAllProcess() {
    for (int i = 0; i < Worker::worker_list->size(); i++) {
        Worker *worker = Worker::worker_list->at(i);
        worker->pids = new std::vector<int>();
        for (int k = 0; k < worker->proc_count; k++) {
            // fork 进程
            int pid = fork();
            if (pid < 0) {
                printf("创建子进程失败\n");
            } else if (pid == 0) {
                // 子进程 处理服务器
                if(worker->socket->is_server)
                    worker->socket->runServer();
                else
                    worker->socket->runConnect(false);
                return;
            } else {
                // 主进程
                worker->pids->push_back(pid);
            }
        }
    }
}

void Worker::initSignal() {
    // 捕获 子进程结束信号
    signal(SIGCHLD, [](int s) -> void {
        printf("收到了子进程被结束的信号 s = %d\n", s);
        int killed_pid = wait(NULL);
        // 检查被结束的进程属于哪个worker 删除pid 重新启动新的进程
        for (int i = 0; i < Worker::worker_list->size(); i++) {
            Worker *worker = Worker::worker_list->at(i);
            std::vector<int>::iterator it;
            for (it = worker->pids->begin(); it != worker->pids->end(); ++it) {
                if (*it == killed_pid) {
                    worker->pids->erase(it);
                    // 重新启动新的进程
                    int pid = fork();
                    if (pid == 0) {
                        if(worker->socket->is_server)
                            worker->socket->runServer();
                        else
                            worker->socket->runConnect(false);
                        return;
                    } else if (pid > 0) {
                        worker->pids->push_back(pid);
                        printf("进程被重新启动 pid = %d\n", pid);
                    }
                    break;
                }
            }
        }
    });
    // 捕获守护进程退出信号
    signal(SIGQUIT, [](int s) {
        // 取消监听子进程退出信号
        signal(SIGCHLD, [](int s){});
        std::vector<Worker *>::iterator workerIt;
        for (workerIt = Worker::worker_list->begin(); workerIt != Worker::worker_list->end(); ++workerIt) {
            Worker *worker = *workerIt;
            for (int i = 0; i < worker->pids->size(); i++) {
                kill(worker->pids->at(i), 9);
            }
        }
        // 结束进程
        exit(0);
    });
}

void Worker::setMasterProcessIsDaemon() {
    // 设置守护进程 1. fork子进程 父进程退出
    int pid = fork();
    if (pid < 0) {
        printf("设置守护进程失败 fork子进程\n");
        exit(-1);
    }
    if (pid > 0) {
        exit(-0);
    }
    // 设置守护进程 2. 子进程使用setsid()函数设置新的会话
    if (setsid() == -1) {
        printf("设置守护进程失败 子进程 setsid\n");
        exit(-1);
    }
    // 设置守护进程 3. fork孙进程 并让子进程退出
    pid = fork();
    if (pid < 0) {
        printf("设置守护进程失败 fork孙进程\n");
        exit(-1);
    }
    if (pid > 0) {
        exit(0);
    }
    // 设置守护进程 4 设置工作目录 /
    chdir("/");
    // 设置守护进程 5 关闭输入流 将输出流定向到文件
    close(0);
    freopen(DAEMON_STDOUT_STREAM_FILE_PATH, "a+", stdout);
    freopen(DAEMON_STDERR_STREAM_FILE_PATH, "a+", stderr);
    umask(0);
    return;
}
